﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Liquifier;


namespace LiquifierTest
{

    public partial class LiquiferAttributesTest
    {
        public delegate int ModifyNumberDelegate(int number);

        [Liquifiable(Serialisation.Public, Serialisation.Explicit, TypeFlags.DelegatesAndEvents)]
        public class ClassWithDelegate
        {
            public ModifyNumberDelegate d;
        }

        [Liquifiable]
        public class ClassWithMethods
        {
            public int Sqr(int value)
            {
                return value * value;
            }

            public int Multiply(int value)
            {
                return value * multiplier;
            }

            public int multiplier = 1;
        }

        [TestMethod]
        public void DoesLiquifierSerialiseDelegates()
        {
            ClassWithDelegate before = new ClassWithDelegate();
            ClassWithMethods resource = new ClassWithMethods();

            before.d = new ModifyNumberDelegate(resource.Sqr);

            var after = DoLiquifify(before);

            Assert.AreEqual(4, after.d(2));

        }

        [Liquifiable(Serialisation.Public, Serialisation.Explicit, TypeFlags.DelegatesAndEvents)]
        public class ClassWithDelegatesAndTheirHosts
        {
            public ClassWithMethods host;
            public ModifyNumberDelegate d;
        }
        
        [TestMethod]
        public void DoesLiquifierMaintainReferenceIntegrityWithDelegates()
        {
            ClassWithDelegatesAndTheirHosts before = new ClassWithDelegatesAndTheirHosts();
            before.host = new ClassWithMethods();

            before.d = new ModifyNumberDelegate(before.host.Multiply);

            before.host.multiplier = 2;

            var after = DoLiquifify(before);

            Assert.AreEqual(4, after.d(2));

            after.host.multiplier = 3;
            Assert.AreEqual(6, after.d(2));
        }

        public delegate void EventHandlerDelegate(int number);

        public class BigContainerClass
        {
            public ClassWithEventsAndSomeHosts eventGenerator = new ClassWithEventsAndSomeHosts();

            public EventSubscriberClass subscriberOne;
            public EventSubscriberClass subscriberTwo;
            public EventSubscriberClass subscriberThree;
        }

        [Liquifiable(Serialisation.Public, Serialisation.Public, TypeFlags.DelegatesAndEvents)]
        public class ClassWithEventsAndSomeHosts
        {
            public event EventHandlerDelegate DoStuffWithNumber;

            public void Go()
            {
                DoStuffWithNumber(5);
            }
        }

        [Liquifiable]
        public class EventSubscriberClass
        {
            public void RecieveNumber(int n)
            {
                internalNumber += n;
            }

            public int internalNumber = 0;
        }

        [TestMethod]
        public void DoesLiquifierSerialiseEvents()
        {
            var before = new BigContainerClass();

            before.subscriberOne = new EventSubscriberClass();
            before.subscriberTwo = before.subscriberOne;
            before.subscriberThree = new EventSubscriberClass();

            before.eventGenerator.DoStuffWithNumber += before.subscriberOne.RecieveNumber;
            before.eventGenerator.DoStuffWithNumber += before.subscriberThree.RecieveNumber;

            var after = DoLiquifify(before);

            after.subscriberOne.internalNumber = 5;
            after.subscriberThree.internalNumber = 10;
            after.eventGenerator.Go();

            Assert.AreEqual(10, after.subscriberOne.internalNumber);
            Assert.AreEqual(10, after.subscriberTwo.internalNumber);
            Assert.AreEqual(15, after.subscriberThree.internalNumber);

            Assert.AreSame(after.subscriberOne, after.subscriberTwo);
            
        }

        //tests to do: 
        //  1. can events/delegates deserialise when target is the owner object
        //  2. 


        public class ObservableListTestClass
        {
            public ObservableList<int> list;

            public ObservableListTestClass()
            {
                list = new ObservableList<int>();
                list.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(list_CollectionChanged);
            }

            void list_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                testvalue += 10;
            }

            public int testvalue = 0;
        }

        [TestMethod]
        public void AreObservableListsEventsSerialised()
        {
            ObservableListTestClass before = new ObservableListTestClass();

            before.list.Add(1);

            Assert.AreEqual(10, before.testvalue);

            var after = DoLiquifify(before);

            after.testvalue = 11;
            after.list.Add(2);

            Assert.AreEqual(2, after.list.Count);
            Assert.AreEqual(21, after.testvalue);

        }

       

    }
}
